package sector.soda.states;

import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.plugins.ZipLocator;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import java.util.logging.Level;

/**
 *
 * @author cheesecake
 */
public class GameState extends BaseGameState {

    private SimpleApplication app;
    private boolean gamePaused = false;
    private DirectionalLight sun;    
    private CharacterControl player;    
    private Vector3f walkDirection = new Vector3f();
    private boolean left = false, right = false, up = false, down = false;

    public GameState() {
        logger.log(Level.INFO, "GameState constructor");
    }

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
        logger.log(Level.INFO, "GameState initialize");
        initialized = true;

        this.app = (SimpleApplication) app;

        setupScene();
        initKeys();
        setUpLight();
    }

    private void setupScene() {
        logger.log(Level.INFO, "GameState setupScene");
        
        BulletAppState bulletAppState = new BulletAppState();
        app.getStateManager().attach(bulletAppState);

        app.getViewPort().setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
        app.getFlyByCamera().setMoveSpeed(100);
        
        Spatial alien = app.getAssetManager().loadModel("Models/Alien/Skin_Sym_Low_6.mesh.j3o");
        alien.setLocalTranslation(5.0f, 6.0f, 8.0f);
        app.getRootNode().attachChild(alien);
        app.getFlyByCamera().setMoveSpeed(30.0f);
        
        CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
        player = new CharacterControl(capsuleShape, 0.05f);
        player.setJumpSpeed(20);
        player.setFallSpeed(30);
        player.setGravity(30);
        player.setPhysicsLocation(new Vector3f(0, 10, 0));
        
        app.getAssetManager().registerLocator("town.zip", ZipLocator.class.getName());

        Spatial sceneModel = app.getAssetManager().loadModel("main.scene");
        sceneModel.setLocalScale(1f);

        CollisionShape sceneShape = CollisionShapeFactory.createMeshShape((Node) sceneModel);
        RigidBodyControl landscape = new RigidBodyControl(sceneShape, 0);
        sceneModel.addControl(landscape);

        app.getRootNode().attachChild(sceneModel);
        bulletAppState.getPhysicsSpace().add(landscape);
        bulletAppState.getPhysicsSpace().add(player);
    }

    private void setUpLight() {
        AmbientLight al = new AmbientLight();
        al.setColor(ColorRGBA.White.mult(1.3f));
        app.getRootNode().addLight(al);

        sun = new DirectionalLight();
        sun.setColor(ColorRGBA.White);
        sun.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
        app.getRootNode().addLight(sun);
    }

    private void initKeys() {
        logger.log(Level.INFO, "GameState initKeys");

        app.getInputManager().addMapping("Lefts", new KeyTrigger(KeyInput.KEY_A));
        app.getInputManager().addMapping("Rights", new KeyTrigger(KeyInput.KEY_D));
        app.getInputManager().addMapping("Ups", new KeyTrigger(KeyInput.KEY_W));
        app.getInputManager().addMapping("Downs", new KeyTrigger(KeyInput.KEY_S));
        app.getInputManager().addMapping("Jumps", new KeyTrigger(KeyInput.KEY_SPACE));
        app.getInputManager().addMapping("Menu", new KeyTrigger(KeyInput.KEY_F10));
        
        app.getInputManager().addListener(actionListener, "Lefts");
        app.getInputManager().addListener(actionListener, "Rights");
        app.getInputManager().addListener(actionListener, "Ups");
        app.getInputManager().addListener(actionListener, "Downs");
        app.getInputManager().addListener(actionListener, "Jumps");
        app.getInputManager().addListener(actionListener, "Menu");
    }

    @Override
    public void cleanup() {
        logger.log(Level.INFO, "GameState cleanup");

        initialized = false;

        app.getRootNode().detachAllChildren();
        app.getRootNode().removeLight(sun);
    }
    private ActionListener actionListener = new ActionListener() {

        public void onAction(String binding, boolean value, float tpf) {
            if (binding.equals("Lefts")) {
                left = value;
            } else if (binding.equals("Rights")) {
                right = value;
            } else if (binding.equals("Ups")) {
                up = value;
            } else if (binding.equals("Downs")) {
                down = value;
            } else if (binding.equals("Jumps")) {
                player.jump();
            }

            if (binding.equals("Menu") && !value) {
                GameState gameState = app.getStateManager().getState(GameState.class);

                if (gameState != null && gameState.isActive()) {
                    app.getStateManager().detach(gameState);

                    MenuState menuState = app.getStateManager().getState(MenuState.class);

                    if (menuState != null && !menuState.isActive()) {
                        menuState.setActive(true);
                    } else {
                        MenuState state = new MenuState();
                        app.getStateManager().attach(state);
                    }
                }
            }
        }
    };
    
    private AnalogListener analogListener = new AnalogListener() {

        public void onAnalog(String name, float value, float tpf) {
            if (!gamePaused) {
                if (name.equals("Right")) {
                }

                if (name.equals("Left")) {
                }
            }
        }
    };

    @Override
    public void update(float tpf) {
        Vector3f camDir = app.getCamera().getDirection().clone().multLocal(0.6f);
        Vector3f camLeft = app.getCamera().getLeft().clone().multLocal(0.4f);
        walkDirection.set(0, 0, 0);
        if (left) {
            walkDirection.addLocal(camLeft);
        }
        if (right) {
            walkDirection.addLocal(camLeft.negate());
        }
        if (up) {
            walkDirection.addLocal(camDir);
        }
        if (down) {
            walkDirection.addLocal(camDir.negate());
        }
        player.setWalkDirection(walkDirection);
        app.getCamera().setLocation(player.getPhysicsLocation());
    }
}